package gosu;

import java.awt.geom.Point2D;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureCoords;
import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;


public class ImageDrawOp extends DrawOp {
  private Image _image;
  private Point2D.Double[] _points;
  private double _z;
  private java.awt.Color[] _colors;
  private int _mode;

  public ImageDrawOp(Image image, double x, double y, double z) {
    this(image, x, y, z, image.getWidth(), image.getHeight(), java.awt.Color.white, Image.DEFAULT);
  }


  public ImageDrawOp(Image image, double x, double y, double z, double factorX, double factorY) {
    this(image, x, y, z, (int) (image.getWidth() * factorX), (int) (image.getHeight() * factorY), java.awt.Color.white, Image.DEFAULT);
  }


  public ImageDrawOp(Image image, double x, double y, double z, double factorX, double factorY, Color color, int mode) {
    this(image, x, y, z, (int) (image.getWidth() * factorX), (int) (image.getHeight() * factorY), color.getAWTColor(), mode);
  }


  protected ImageDrawOp(Image image, double x, double y, double z, int width, int height, java.awt.Color color, int mode) {
    _image = image;

    _points = new Point2D.Double[4];
    _points[0] = new Point2D.Double(x, y);
    _points[1] = new Point2D.Double(x + width, y);
    _points[2] = new Point2D.Double(x + width, y + height);
    _points[3] = new Point2D.Double(x, y + height);

    _z = z;
    _mode = mode;

    _colors = new java.awt.Color[] {color, color, color, color};
  }


  public ImageDrawOp(Image image, double x1, double y1, Color c1,
                                      double x2, double y2, Color c2,
                                      double x3, double y3, Color c3,
                                      double x4, double y4, Color c4, 
                                      double z, int mode) {
    _image = image;
    _points = new Point2D.Double[] {new Point2D.Double(x1, y1),
                                    new Point2D.Double(x2, y2),
                                    new Point2D.Double(x4, y4),
                                    new Point2D.Double(x3, y3)};
    _z = z;
    _mode = mode;
    _colors = new java.awt.Color[] {c1.getAWTColor(), c2.getAWTColor(),
                                    c4.getAWTColor(), c3.getAWTColor()};
  }


  /**
   * Draws a line.
   */
  public ImageDrawOp(double x1, double y1, Color c1, double x2, double y2, Color c2) {
    this(x1, y1, c1, x2, y2, c2, 0, Image.DEFAULT);
  }


  /**
   * Draws a line.
   */
  public ImageDrawOp(double x1, double y1, Color c1, double x2, double y2, Color c2, double z, int mode) {
    _points = new Point2D.Double[] {new Point2D.Double(x1, y1), new Point2D.Double(x2, y2)};
    _colors = new java.awt.Color[] {c1.getAWTColor(), c2.getAWTColor()};
    _z = z;
    _mode = mode;
  }


  /**
   * Draws a triangle.
   */
  public ImageDrawOp(double x1, double y1, Color c1,
                     double x2, double y2, Color c2,
                     double x3, double y3, Color c3) {
    this(x1, y1, c1, x2, y2, c2, x3, y3, c3, 0, Image.DEFAULT);
  }


  /**
   * Draws a triangle.
   */
  public ImageDrawOp(double x1, double y1, Color c1,
                     double x2, double y2, Color c2,
                     double x3, double y3, Color c3, double z, int mode) {
    _points = new Point2D.Double[] {new Point2D.Double(x1, y1), 
                                    new Point2D.Double(x2, y2),
                                    new Point2D.Double(x3, y3)};
    _colors = new java.awt.Color[] {c1.getAWTColor(), 
                                    c2.getAWTColor(),
                                    c3.getAWTColor()};
    _z = z;
    _mode = mode;
  }


  /**
   * Draws a quad.
   */
  public ImageDrawOp(double x1, double y1, Color c1,
                     double x2, double y2, Color c2,
                     double x3, double y3, Color c3,
                     double x4, double y4, Color c4) {
    this(x1, y1, c1, x2, y2, c2, x3, y3, c3, x4, y4, c4, 0, Image.DEFAULT);
  }


  /**
   * Draws a quad.
   */
  public ImageDrawOp(double x1, double y1, Color c1,
                     double x2, double y2, Color c2,
                     double x3, double y3, Color c3,
                     double x4, double y4, Color c4, double z, int mode) {

    _points = new Point2D.Double[] {new Point2D.Double(x1, y1), 
                                    new Point2D.Double(x2, y2),
                                    new Point2D.Double(x4, y4),
                                    new Point2D.Double(x3, y3)};

    _colors = new java.awt.Color[] {c1.getAWTColor(), 
                                    c2.getAWTColor(),
                                    c4.getAWTColor(),
                                    c3.getAWTColor()};
    _z = z;
    _mode = mode;
  }


  public double getZ() { return _z; }


  public void execute() {
    GL gl = GLU.getCurrentGL();

    if (_mode == Image.ADDITIVE) {
      gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE);
    } else {
      gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA);
    }

    Texture texture = null;
    TextureCoords coords = null;
    if (_image != null) {
      texture = _image.getTexture();
      texture.enable();
      texture.bind();
      //texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
      //texture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
      if (_image.hasSoftBorders()) {
        coords = texture.getSubImageTexCoords(1, 1, _image.getWidth() + 1, _image.getHeight() + 1);
      } else {
        coords = texture.getImageTexCoords();
      }
    }

    if (_points.length == 2) {
        gl.glBegin(GL.GL_LINES);
    } else if (_points.length == 3) {
        gl.glBegin(GL.GL_TRIANGLES);
    } else { // 4
        gl.glBegin(GL.GL_QUADS);
    }


    for (int i = 0; i < _points.length; i++) {
      // JOGL textures have premultiplied colors
      float a = _colors[i].getAlpha() / 255.0f;
      float r = a * _colors[i].getRed() / 255.0f;
      float g = a * _colors[i].getGreen() / 255.0f;
      float b = a * _colors[i].getBlue() / 255.0f;
      gl.glColor4f(r, g, b, a);

      if (texture != null) {
        switch (i) {
          case 0:
            gl.glTexCoord2f(coords.left(), coords.top());
            break;
          case 1:
            gl.glTexCoord2f(coords.right(), coords.top());
            break;
          case 2:
            gl.glTexCoord2f(coords.right(), coords.bottom());
            break;
          case 3:
            gl.glTexCoord2f(coords.left(), coords.bottom());
            break;
        }
      }

      gl.glVertex2d(_points[i].x, _points[i].y);
    }

    gl.glEnd();

    if (texture != null) texture.disable();
  }
}
